﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Revit;
using YJKCodeBase.WinForm;

namespace FormatPainter.FormatPainter
{
	public class FormatPainterManager
	{
		public FormatPainterManager(ExternalCommandData cmdData)
		{
			this.m_Revit = cmdData;
			this.m_Doc = this.m_Revit.Application.ActiveUIDocument.Document;
		}

		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public Result Do(ref string msg)
		{
			Element element = null;
			if (!this.SelelctElement(null, BuiltInCategory.INVALID, "选择源实体", ref element))
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			Type type = element.GetType();
            BuiltInCategory integerValue = (BuiltInCategory)element.Category.Id.IntegerValue;
			this.PaintInfos(element, type, element.Category.Name, integerValue);
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private bool SelelctElement(Type type, BuiltInCategory category, string statusPrompt, ref Element element)
		{
			Reference reference = null;
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			try
			{
				reference = selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element, new FilterByElementType(type, category), statusPrompt);
			}
			catch (Exception)
			{
				return false;
			}
			if (reference == null)
			{
				return false;
			}
			element = this.m_Doc.GetElement(reference);
			return true;
		}

		private bool SelelctElements(Type type, BuiltInCategory category, string statusPrompt, ref List<Element> elements)
		{
			IList<Element> list = null;
			Selection selection = this.m_Revit.Application.ActiveUIDocument.Selection;
			try
			{
				list = selection.PickElementsByRectangle(new FilterByElementType(type, category), statusPrompt);
			}
			catch (Exception)
			{
				return false;
			}
			foreach (Element element in list)
			{
				if (element != null)
				{
					elements.Add(element);
				}
			}
			return true;
		}

		private void PaintInfos(Element sourceElement, Type type, string categoryName, BuiltInCategory category)
		{
			List<KeyValuePair<string, string>> parameterPairList = this.GetParameterPairList(sourceElement);
			FormatPainterForm formatPainterForm = new FormatPainterForm(parameterPairList);
			formatPainterForm.Show(FormatPainterManager._hWndRevit);
			int wMsg = 7;
			FormatPainterManager.SendMessage(FormatPainterManager._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			try
			{
				List<Element> list = new List<Element>();
				string statusPrompt = "请框选 " + categoryName + " 实体";
				while (this.SelelctElements(type, category, statusPrompt, ref list))
				{
					foreach (Element element in list)
					{
						if (element != null)
						{
							this.CopyInfos(sourceElement, parameterPairList, formatPainterForm.CheckedStateList(), element);
						}
					}
					list.Clear();
				}
			}
			catch (Exception ex)
			{
				string message = ex.Message;
				formatPainterForm.Close();
			}
			formatPainterForm.Close();
		}

		private List<KeyValuePair<string, string>> GetParameterPairList(Element element)
		{
			List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
			ParameterSet parameters = element.Parameters;
			foreach (object obj in parameters)
			{
				Parameter parameter = (Parameter)obj;
				if (!parameter.IsReadOnly && !parameter.IsShared)
				{
					Definition definition = parameter.Definition;
					InternalDefinition internalDefinition = definition as InternalDefinition;
					if (internalDefinition != null)
					{
						string value = "";
                        switch ((int)parameter.StorageType)
						{
						case 1:
							value = parameter.AsInteger().ToString();
							break;
						case 2:
							value = AssistFunc.feetToMM(parameter.AsDouble()).ToString("f2");
							break;
						case 3:
							value = parameter.AsString();
							break;
						case 4:
							value = this.GetIdParameterInfo(parameter.AsElementId());
							break;
						}
						KeyValuePair<string, string> item = new KeyValuePair<string, string>(internalDefinition.Name, value);
						list.Add(item);
					}
				}
			}
			list.Sort(new ParameterPairsComparer());
			return list;
		}

		private string GetIdParameterInfo(ElementId id)
		{
			if (null == id || id == ElementId.InvalidElementId)
			{
				return "";
			}
			return this.m_Doc.GetElement(id).Name;
		}

		private void CopyInfos(Element sourceElement, List<KeyValuePair<string, string>> parameterPairList, List<bool> checkedStateList, Element element)
		{
			Transaction transaction = new Transaction(this.m_Doc);
			transaction.Start("copy parameters");
			ParameterSet parameters = sourceElement.Parameters;
			List<Parameter> list = new List<Parameter>();
			foreach (object obj in parameters)
			{
				Parameter item = (Parameter)obj;
				list.Add(item);
			}
			for (int i = 0; i < list.Count; i++)
			{
				Parameter parameter = list[i];
				if (!parameter.IsReadOnly && !parameter.IsShared)
				{
					Definition definition = parameter.Definition;
					InternalDefinition interDefinition = definition as InternalDefinition;
					if (interDefinition != null)
					{
						Parameter parameter2;
                        if ((int)interDefinition.BuiltInParameter == -1)
						{
							parameter2 = element.GetParameter(definition.Name);
						}
						else
						{
							parameter2 = element.get_Parameter(interDefinition.BuiltInParameter);
						}
						if (parameter2 != null)
						{
							int num = parameterPairList.FindIndex((KeyValuePair<string, string> value) => value.Key.CompareTo(interDefinition.Name) == 0);
							if (-1 != num && checkedStateList[num])
							{
								if (parameter2.IsReadOnly)
								{
									list.Add(parameter);
								}
								else
								{
									try
									{
                                        switch ((int)parameter.StorageType)
										{
										case 1:
											parameter2.Set(parameter.AsInteger());
											break;
										case 2:
											parameter2.Set(parameter.AsDouble());
											break;
										case 3:
											parameter2.Set(parameter.AsString());
											break;
										case 4:
											parameter2.Set(parameter.AsElementId());
											break;
										}
									}
									catch (Exception ex)
									{
										string message = ex.Message;
									}
								}
							}
						}
					}
				}
			}
			transaction.Commit();
		}

		public static WindowHandle _hWndRevit;

		private ExternalCommandData m_Revit;

		private Document m_Doc;
	}
}
